/*
 * IJA2011, Board game "Clovece nezlob se"
 * grp108
 * Tomáš Mičiak,xmicia00
 * Andrej Martinák, xmarti51
 *
 */

package src.clovece.game;

import java.util.ArrayList;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.ImageIcon;
import src.clovece.ErrorDialog;
import src.clovece.GameFrame;
import src.clovece.GameInfoPanel;
import src.clovece.WinDialog;

/**
 * Class serving as a game engine for the game.
 * Provides methods for creating game board, managing the game process, etc.
 * This class is created in singleton pattern
 */
public class GameManagement {
    private static GameManagement instance = new GameManagement();
    private GameInfo gameInfo = GameInfo.getGameInfoInstance();
    private Load load = Load.getLoadInstance();
    private GameInfoPanel infoPanel = null;
    private GameFrame gameFrame = null;
    private boolean stop = false;

    
    private GameManagement() {
        super();
    }

    /**
     * Getter for the only instance of the class
     * @return GameManagement
     */
    public static GameManagement getGameManagementInstance() {
        return GameManagement.instance;
    }

    /**
     *  Starts new game
     */
    public void startNewGame() {
        Runnable r = new Runnable() {
            public void run() {
                GameManagement.getGameManagementInstance().yourTurn(0);
                GameInfo.getGameInfoInstance().setYourPosition(0);
            }
        };
        new Thread(r).start();
    }

    /**
     *  starts loaded game
     */
    public void startLoadedGame() {
        Runnable r = new Runnable() {
            public void run() {
                GameManagement.getGameManagementInstance().yourTurn(0);
                GameInfo.getGameInfoInstance().setYourPosition(0);
            }
        };
        new Thread(r).start();
    }

    /**
     *  starts joined game
     */
    public void startJoinedGame() {
        Runnable r = new Runnable() {
            public void run() {
                GameManagement.getGameManagementInstance().yourTurn(0);
                GameManagement.getGameManagementInstance().getInfoPanel().getThrowButton().setEnabled(false);
            }
        };
        new Thread(r).start();
    }

    /**
     *  starts joined game
     */
    public void yourTurn(int player) {
        this.infoPanel.unpaintNextTurn(this.gameInfo.getPlayerOnTurn());
        this.gameInfo.setPlayerOnTurn(player);
        this.infoPanel.paintNextTurn(this.gameInfo.getPlayerOnTurn());
        this.infoPanel.repaintInfoPanel();
        // local human
        if(this.gameInfo.getPlayers()[this.gameInfo.getPlayerOnTurn()].getUserControled()) {
            this.infoPanel.getThrowButton().setEnabled(true);
            System.out.println("________________________________________________");
            System.out.println("HUMAN ON TURN");
            this.infoPanel.getJumpLabel().setText("Jump: ---");
            this.infoPanel.getPreferHomeLabel().setText("Prefer Home: ---");
            this.infoPanel.getPreferNewLabel().setText("Prefer New: ---");
            return;
        }
        // computer
        else {
            if(this.gameInfo.getLocalGame()) {
                System.out.println("________________________________________________");
                System.out.println("COMPUTER ON TURN");
                this.gameInfo.getPlayers()[this.gameInfo.getPlayerOnTurn()].setOnTurn(true);
                AiPlayer cpu = (AiPlayer) this.gameInfo.getPlayers()[this.gameInfo.getPlayerOnTurn()];
                if(cpu.getRandomMove()) this.infoPanel.getJumpLabel().setText("Jump: random");
                else this.infoPanel.getJumpLabel().setText("Jump: longest");
                if(cpu.getPreferHome()) this.infoPanel.getPreferHomeLabel().setText("Prefer Home: yes");
                else this.infoPanel.getPreferHomeLabel().setText("Prefer Home: No");
                if(cpu.getPreferNew()) this.infoPanel.getPreferNewLabel().setText("Prefer New: yes");
                else this.infoPanel.getPreferNewLabel().setText("Prefer New: no");
                cpu.throwDie();
            }
            // online opponent
            else {
                System.out.println("________________________________________________");
                System.out.println("ONLINE ON TURN");
                this.infoPanel.getJumpLabel().setText("Jump: ---");
                this.infoPanel.getPreferHomeLabel().setText("Prefer Home: ---");
                this.infoPanel.getPreferNewLabel().setText("Prefer New: ---");
                Runnable r = new Runnable() {
                    public void run() {
                        GameManagement gm = GameManagement.getGameManagementInstance();
                        Multiplayer mp =  new Multiplayer();
                        System.out.println("pred");
                        int symbol = 0;
                        int figurine = 0;
                        int field = 0;

                        try {
                            symbol = mp.readValue();
                        }
                        catch(Exception e) {
                            ErrorDialog ed = new ErrorDialog(gameFrame, true, "Protihrac sa odpojil.");
                            GameManagement.getGameManagementInstance().getGameFrame().getGameBoard().setEnabled(false);
                            GameManagement.getGameManagementInstance().getGameFrame().setGameBoard(null);
                            return;
                        }
                        gm.infoPanel.getDie().repaintDie(symbol);

                        try {
                            figurine = mp.readValue();
                        }
                        catch(Exception e) {
                            ErrorDialog ed = new ErrorDialog(gameFrame, true, "Protihrac sa odpojil.");
                            GameManagement.getGameManagementInstance().getGameFrame().getGameBoard().setEnabled(false);
                            GameManagement.getGameManagementInstance().getGameFrame().setGameBoard(null);
                            return;
                        }
                        
                        try {
                            field = mp.readValue();
                        }
                        catch(Exception e) {
                            ErrorDialog ed = new ErrorDialog(gameFrame, true, "Protihrac sa odpojil.");
                            GameManagement.getGameManagementInstance().getGameFrame().getGameBoard().setEnabled(false);
                            GameManagement.getGameManagementInstance().getGameFrame().setGameBoard(null);
                            return;
                        }

                        System.out.println(figurine);
                        System.out.println(field);
                        /*
                         * pohyb figurky
                         */
                        if(figurine != -1 && field != -1) {
                            int actPos = gm.gameInfo.getPlayers()[gm.gameInfo.getPlayerOnTurn()].getFigurines()[figurine].getActualPosition();
                            if(actPos != -1) gm.gameInfo.getFields()[actPos].setOccupied(false);
                            gm.gameInfo.getPlayers()[gm.gameInfo.getPlayerOnTurn()].getFigurines()[figurine].setActualPosition(field);
                            gm.gameInfo.getPlayers()[gm.gameInfo.getPlayerOnTurn()].getFigurines()[figurine].setBounds(gm.gameInfo.getFields()[field].getX(), gm.gameInfo.getFields()[field].getY(), 40, 40);
                            gm.gameInfo.getFields()[field].setOccupied(false);
                            if(gm.gameInfo.getFields()[field].getSaveHouse()) {
                                gm.gameInfo.getPlayers()[gm.gameInfo.getPlayerOnTurn()].getFigurines()[figurine].setGameCompleted(true);

                                boolean winner = true;
                                for(int i = 0; i < 4; i++) {
                                    if(!gm.gameInfo.getPlayers()[gm.gameInfo.getPlayerOnTurn()].getFigurines()[i].getGameCompleted()) {
                                        winner = false;
                                    }
                                }
                                if(winner) {
                                    WinDialog wd = new WinDialog(gm.gameFrame, true, gm.gameInfo.getPlayerOnTurn(), gm.gameInfo.getPlayers()[gm.gameInfo.getPlayerOnTurn()].getNickname());
                                    wd.setVisible(true);
                                    gm.infoPanel.getThrowButton().setEnabled(false);
                                    return;
                                }
                            }
                        }
                        gm.yourTurn((gm.gameInfo.getPlayerOnTurn()+1)%gm.gameInfo.getNumberOfPlayers());
                    }
                };
                new Thread(r).start();
            }
        }
    }

    /**
     *  starts joined game
     */
    public void dieThrown() {
        this.gameInfo.getPlayers()[this.gameInfo.getPlayerOnTurn()].setOnTurn(true);
        this.infoPanel.getThrowButton().setEnabled(false);
        // computer / online human opponent
        if(!this.gameInfo.getPlayers()[this.gameInfo.getPlayerOnTurn()].getUserControled()) {
            if(this.gameInfo.getLocalGame()) {
                if(this.canMove()) {
                    System.out.println("CPU n." + this.gameInfo.getPlayerOnTurn() + " will move with figurine.");
                    AiPlayer cpu = (AiPlayer) this.gameInfo.getPlayers()[this.gameInfo.getPlayerOnTurn()];
                    cpu.performMove();
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException ex) {
                        Logger.getLogger(GameManagement.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
                else {
                    System.out.println("Computer can't move");
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException ex) {
                        Logger.getLogger(GameManagement.class.getName()).log(Level.SEVERE, null, ex);
                    }
                    this.yourTurn((this.gameInfo.getPlayerOnTurn()+1)%this.gameInfo.getNumberOfPlayers());
                }
            }
        }
        //local human player
        else {
            if(!this.canMove()) {
                if(!this.gameInfo.getLocalGame()) {
                    Multiplayer mp = new Multiplayer();
                    mp.writeValue(this.gameInfo.getDie());
                    mp.writeValue(-1);
                    mp.writeValue(-1);
                }
                System.out.println("Human player can't move");
                try {
                    Thread.sleep(500);
                } catch (InterruptedException ex) {
                    Logger.getLogger(GameManagement.class.getName()).log(Level.SEVERE, null, ex);
                }
                this.yourTurn((this.gameInfo.getPlayerOnTurn()+1)%this.gameInfo.getNumberOfPlayers());
            }
            else {
                if(!this.gameInfo.getLocalGame()) {
                    Multiplayer mp = new Multiplayer();
                    mp.writeValue(this.gameInfo.getDie());
                }   
            }
        }
    }

    /**
     *  starts joined game
     */
    public boolean canMove() {
        Figurine[] figurines = this.gameInfo.getPlayers()[this.gameInfo.getPlayerOnTurn()].getFigurines();
        this.gameInfo.setPosibleMovesFields(new ArrayList<GameField>());
        this.gameInfo.setPosibleMovesFigurines(new ArrayList<Figurine>());
        int index = 0;
        int jumpLength = 0;
        boolean canMove = false;
        for(int i = 0; i < 4; i++) {
            if(figurines[i].getActualPosition() == -1) {
                if(this.gameInfo.getDie() != 5) continue;
                else {
                    if(!this.gameInfo.getFields()[figurines[i].getStartingPosition()].getOccupied()) {
                        this.gameInfo.getPlayers()[this.gameInfo.getPlayerOnTurn()].getFigurines()[i].setCanMove(true);
                        this.gameInfo.getFields()[figurines[i].getStartingPosition()].addMoveAllowed(i);
                        canMove = true;
                        this.gameInfo.getPosibleMovesFields().add(this.gameInfo.getFields()[figurines[i].getStartingPosition()]);
                        this.gameInfo.getPosibleMovesFigurines().add(this.gameInfo.getPlayers()[this.gameInfo.getPlayerOnTurn()].getFigurines()[i]);
                    }
                }
            }
            else if(figurines[i].getCounter() + 6 > this.gameInfo.getGameBoardSize()-1) {
                boolean sameFieldButOccupiedInFrontOfTheHouse = false;
                for(int j = 1; j <= this.gameInfo.getGameBoardSize()-figurines[i].getCounter()-1; j++) {
                    if(this.gameInfo.getFields()[(figurines[i].getActualPosition()+j)%this.gameInfo.getGameBoardSize()].getColor() == this.gameInfo.getDie()) {
                        if(this.gameInfo.getFields()[(figurines[i].getActualPosition()+j)%this.gameInfo.getGameBoardSize()].getOccupied()
                        && this.gameInfo.getFields()[(figurines[i].getActualPosition()+j)%this.gameInfo.getGameBoardSize()].getPosition() != figurines[i].getActualPosition()) {
                            sameFieldButOccupiedInFrontOfTheHouse = true;
                            break;
                        }
                        this.gameInfo.getPlayers()[this.gameInfo.getPlayerOnTurn()].getFigurines()[i].setCanMove(true);
                        this.gameInfo.getFields()[(figurines[i].getActualPosition()+j)%this.gameInfo.getGameBoardSize()].addMoveAllowed(i);
                        canMove = true;
                        this.gameInfo.getPosibleMovesFields().add(this.gameInfo.getFields()[(figurines[i].getActualPosition()+j)%this.gameInfo.getGameBoardSize()]);
                        this.gameInfo.getPosibleMovesFigurines().add(this.gameInfo.getPlayers()[this.gameInfo.getPlayerOnTurn()].getFigurines()[i]);
                        break;
                    }
                }
                if(!this.gameInfo.getPosibleMovesFigurines().contains(this.gameInfo.getPlayers()[this.gameInfo.getPlayerOnTurn()].getFigurines()[i])
                        && !sameFieldButOccupiedInFrontOfTheHouse) {
                    System.out.println("uz som skoro doma" + figurines[i].getPlayer().getPosition());
                    int toHome;
                    int startAt;
                    if(figurines[i].getCounter() <= this.gameInfo.getGameBoardSize()-1) {
                        toHome = 6 - (this.gameInfo.getGameBoardSize()-1-figurines[i].getCounter());
                        startAt = this.gameInfo.getGameBoardSize()-1+4*figurines[i].getPlayer().getPosition();
                    }
                    else {
                        toHome = this.gameInfo.getGameBoardSize()-1+4*(figurines[i].getPlayer().getPosition()+1)-figurines[i].getActualPosition();
                        startAt = figurines[i].getActualPosition();
                    }
                    for(int j = 1; j <= toHome; j++) {
                        if(j + startAt >= this.gameInfo.getGameBoardSize()+4*(figurines[i].getPlayer().getPosition()+1)) {
                            break;
                        }
                        if(this.gameInfo.getFields()[startAt+j].getColor() == this.gameInfo.getDie()
                                && !this.gameInfo.getFields()[startAt+j].getOccupied()) {
                            this.gameInfo.getPlayers()[this.gameInfo.getPlayerOnTurn()].getFigurines()[i].setCanMove(true);
                            this.gameInfo.getFields()[startAt+j].addMoveAllowed(i);
                            canMove = true;
                            this.gameInfo.getPosibleMovesFields().add(this.gameInfo.getFields()[startAt+j]);
                            this.gameInfo.getPosibleMovesFigurines().add(this.gameInfo.getPlayers()[this.gameInfo.getPlayerOnTurn()].getFigurines()[i]);
                            break;
                        }
                    }
                }
            }
            else {
                this.gameInfo.getPlayers()[this.gameInfo.getPlayerOnTurn()].getFigurines()[i].setCanMove(true);
                for(int j = 1; j <= 6; j++) {
                    if(this.gameInfo.getFields()[(figurines[i].getActualPosition()+j)%this.gameInfo.getGameBoardSize()].getColor() == this.gameInfo.getDie()
                            && !this.gameInfo.getFields()[(figurines[i].getActualPosition()+j)%this.gameInfo.getGameBoardSize()].getOccupied()) {
                        this.gameInfo.getFields()[(figurines[i].getActualPosition()+j)%this.gameInfo.getGameBoardSize()].addMoveAllowed(i);
                        canMove = true;
                        this.gameInfo.getPosibleMovesFields().add(this.gameInfo.getFields()[(figurines[i].getActualPosition()+j)%this.gameInfo.getGameBoardSize()]);
                        this.gameInfo.getPosibleMovesFigurines().add(this.gameInfo.getPlayers()[this.gameInfo.getPlayerOnTurn()].getFigurines()[i]);
                        break;
                    }
                }
            }
        }
        for(int i = 0; i < this.gameInfo.getPosibleMovesFields().size(); i++) {
            System.out.println("Figurine n." + this.gameInfo.getPosibleMovesFigurines().get(i).getNumber() + " on position: " + this.gameInfo.getPosibleMovesFigurines().get(i).getActualPosition() + " can move to field: " + this.gameInfo.getPosibleMovesFields().get(i).getPosition());
        }
        return canMove;
    }

    /**
     * Sets actually picked Figurine
     * @param Figurine figurine being picked up
     */
    public void selectFigurine(Figurine f) {
        if(this.gameInfo.getSelectedFigurine() != null) {
            this.deselectFigurine();
        }
        f.select();
        this.gameInfo.setSelectedFigurine(f);
    }

    /**
     * Moves actually picked Figurine
     * @param GameField game field on which will Figurine move
     */
    public void moveFigurine(GameField gf) {
        if(this.gameInfo.getSelectedFigurine() != null) {
            boolean match = false;
            if(gf.getMoveAllowed().isEmpty()) {
                this.gameInfo.getSelectedFigurine().deselect();
                this.gameInfo.setSelectedFigurine(null);
                return;
            }
            for(int i = 0; i < gf.getMoveAllowed().size(); i++) {
                if(gf.getMoveAllowed().get(i).intValue() == this.gameInfo.getSelectedFigurine().getNumber()) {
                    match = true;
                }
            }
            if(match == false) {
                this.gameInfo.getSelectedFigurine().deselect();
                return;
            }
            this.gameInfo.getSelectedFigurine().moveFigurine(gf.getX(),gf.getY());
            
            // pocet policok o ktere se posuni ten vyjebani panak
            int old_pos = this.gameInfo.getSelectedFigurine().getActualPosition();
            int new_pos = gf.getPosition();

            if(old_pos == -1) {
                this.gameInfo.getSelectedFigurine().setCounter(0);
            }
            else if(old_pos > new_pos) {
                this.gameInfo.getSelectedFigurine().setCounter(this.gameInfo.getSelectedFigurine().getCounter()+this.gameInfo.getGameBoardSize()-(old_pos-new_pos));
            }
            else if(new_pos > old_pos) {
                if(new_pos > this.gameInfo.getGameBoardSize()-1) {
                    this.gameInfo.getSelectedFigurine().setCounter(new_pos);
                }
                else {
                    this.gameInfo.getSelectedFigurine().setCounter(this.gameInfo.getSelectedFigurine().getCounter()+(new_pos-old_pos));
                }
            }
            if(this.gameInfo.getSelectedFigurine().getActualPosition() != -1) this.gameInfo.getFields()[this.gameInfo.getSelectedFigurine().getActualPosition()].setOccupied(false);
            this.gameInfo.getSelectedFigurine().setActualPosition(gf.getPosition());
            this.gameInfo.getFields()[this.gameInfo.getSelectedFigurine().getActualPosition()].setOccupied(true);
            if(!this.gameInfo.getLocalGame()) {
                Multiplayer mp = new Multiplayer();
                mp.writeValue(this.gameInfo.getSelectedFigurine().getNumber());
                mp.writeValue(this.gameInfo.getSelectedFigurine().getActualPosition());
            }
            System.out.print("FIGURINE n.: " + this.gameInfo.getSelectedFigurine().getNumber());
            System.out.print(" has position after move: " + this.gameInfo.getSelectedFigurine().getActualPosition());
            System.out.println(" and counter: " + this.gameInfo.getSelectedFigurine().getCounter());
            //TODO vykonany move
            for(int i = 0; i < this.gameInfo.getGameBoardSize()+4*this.gameInfo.getNumberOfPlayers(); i++) {
                this.gameInfo.getFields()[i].getMoveAllowed().clear();
            }
            for(int i = 0; i < 4; i++) {
                this.gameInfo.getPlayers()[this.gameInfo.getPlayerOnTurn()].getFigurines()[i].setCanMove(false);
            }
            //TODO when completed, uncomment this section
            boolean winner = false;
            if(gf.getSaveHouse()) {
                winner = true;
                this.gameInfo.getSelectedFigurine().setGameCompleted(true);
                for(int i = 0; i < 4; i++) {
                    if(!this.gameInfo.getPlayers()[this.gameInfo.getPlayerOnTurn()].getFigurines()[i].getGameCompleted()) {
                        winner = false;
                    }
                }
            }
            if(winner) {
                WinDialog wd = new WinDialog(this.gameFrame, true, this.gameInfo.getPlayerOnTurn(), this.gameInfo.getPlayers()[this.gameInfo.getPlayerOnTurn()].getNickname());
                wd.setVisible(true);
                this.infoPanel.getThrowButton().setEnabled(false);
                return;
            }
            this.gameInfo.getPlayers()[this.gameInfo.getPlayerOnTurn()].setOnTurn(false);
            this.gameInfo.setSelectedFigurine(null);
            System.out.println("NEXT IS PLAYER ON POSITION: " + (this.gameInfo.getPlayerOnTurn()+1)%this.gameInfo.getNumberOfPlayers());
            this.yourTurn((this.gameInfo.getPlayerOnTurn()+1)%this.gameInfo.getNumberOfPlayers());
        }
    }

    /**
     * Unsets actually picked Figurine
     */
    public void deselectFigurine() {
        if(this.gameInfo.getSelectedFigurine() != null) {
            this.gameInfo.getSelectedFigurine().deselect();
            this.gameInfo.setSelectedFigurine(null);
        }
    }

    /**
     * Changes graphic mode and players figurines
     */
    public void repaintBoard() {
        for(int i = 0; i < this.gameInfo.getGameBoardSize()+4*this.gameInfo.getNumberOfPlayers(); i++) {
            this.gameInfo.getFields()[i].setIcon(this.getGameFieldIcon(this.gameInfo.getGraphicMode(), this.gameInfo.getFields()[i].getColor()));
        }
        for(int i = 0; i < this.gameInfo.getNumberOfPlayers(); i++) {
            for(int j = 0; j < 4; j++) {
                if(i == 0) {
                    this.gameInfo.getPlayers()[i].getFigurines()[j].setIcon(this.getFigurineIcon(this.gameInfo.getGraphicMode(), this.gameInfo.getChosenFigurine()));
                    this.gameInfo.getPlayers()[i].getFigurines()[j].setFigurine(this.gameInfo.getChosenFigurine());
                    this.gameInfo.getPlayers()[i].getFigurines()[j].setGameSet(this.gameInfo.getGraphicMode());
                }
                else if(this.gameInfo.getChosenFigurine() == i) {
                    this.gameInfo.getPlayers()[i].getFigurines()[j].setIcon(this.getFigurineIcon(this.gameInfo.getGraphicMode(), 0));
                    this.gameInfo.getPlayers()[i].getFigurines()[j].setFigurine(0);
                    this.gameInfo.getPlayers()[i].getFigurines()[j].setGameSet(this.gameInfo.getGraphicMode());
                }
                else {
                    this.gameInfo.getPlayers()[i].getFigurines()[j].setIcon(this.getFigurineIcon(this.gameInfo.getGraphicMode(), i));
                    this.gameInfo.getPlayers()[i].getFigurines()[j].setFigurine(i);
                    this.gameInfo.getPlayers()[i].getFigurines()[j].setGameSet(this.gameInfo.getGraphicMode());
                }
            }
        }
        this.infoPanel.repaintInfoPanel();
    }

    public ImageIcon getFigurineIcon(int gameSet, int figurine) {
        ImageIcon icon = new ImageIcon(System.getProperty("user.dir")+ System.getProperty("file.separator")
                  + "lib" + System.getProperty("file.separator") + "img"
                  + System.getProperty("file.separator") + "figurine" + gameSet + figurine + "a" + ".png");
        return icon;
    }

    public ImageIcon getGameFieldIcon(int gameSet, int field) {
        ImageIcon icon = new ImageIcon(System.getProperty("user.dir")+ System.getProperty("file.separator")
                  + "lib" + System.getProperty("file.separator") + "img"
                  + System.getProperty("file.separator") + gameSet + field + ".png");
        return icon;
    }

    /**
     * Creates all elements of the game board for new singleplayer game
     */
    public void createNewSingleplayerGameBoard() {
        this.createGameFields(null);
        this.createSingleplayerPlayers();
        this.gameInfo.setHasStarted(true);
    }

    /**
     * Creates all elements of the game board for new multiplayer game
     */
    public void createNewMultiplayerGameBoard() {
        this.createGameFields(this.gameInfo.getGeneratedValues());
        if(this.gameInfo.getPlayers() != null) {
            this.gameInfo.setPlayers(null);
        }
        Player[] players = new Player[this.gameInfo.getNumberOfPlayers()];
        this.gameInfo.setPlayers(players);
        this.createMultiplayerPlayers();
        this.gameInfo.setHasStarted(true);
    }

    /**
     * Creates all elements of the game board for loaded singleplayer game
     */
    public void createLoadedSingleplayerGameBoard() {
        this.gameInfo.setNumberOfPlayers(this.load.getNumberOfPlayers());
        this.gameInfo.setGameBoardSize(this.load.getGameBoardSize());
        this.gameInfo.setPlayerNickname(this.load.getPlayerNickname(),0);
        this.gameInfo.setChosenFigurine(this.load.getChosenFigurine());
        this.gameInfo.setPlayerOnTurn(this.load.getPlayerOnTurn());
        this.gameInfo.setGeneratedValues(this.load.getGeneratedValues());
        this.gameInfo.setGamePhase(this.load.getGamePhase());
        this.gameInfo.setGraphicMode(this.load.getGraphicMode());
        this.gameInfo.setPlayerNickname(this.load.getPlayerNickname(),0);
        this.gameInfo.setDie(this.load.getDie());
        this.createGameFields(this.load.getGeneratedValues());
        this.loadPlayers();
        this.gameInfo.setHasStarted(true);
    }

    /**
     * Creates all elements of the game board for loaded multiplayer game
     */
    public void createLoadedMultiplayerGameBoard() {
        this.createGameFields(this.gameInfo.getGeneratedValues());
        if(this.gameInfo.getPlayers() != null) {
            this.gameInfo.setPlayers(null);
        }
        Player[] players = new Player[this.gameInfo.getNumberOfPlayers()];
        this.gameInfo.setPlayers(players);
        this.createMultiplayerPlayers();
        this.gameInfo.setHasStarted(true);
    }

    /**
     * Creates all elements of the game board for joined multiplayer game
     */
    public void createJoinedMultiplayerGameBoard() {
        this.createGameFields(this.gameInfo.getGeneratedValues());
        if(this.gameInfo.getPlayers() != null) {
            this.gameInfo.setPlayers(null);
        }
        Player[] players = new Player[this.gameInfo.getNumberOfPlayers()];
        this.gameInfo.setPlayers(players);
        this.createMultiplayerPlayers();
        this.gameInfo.setHasStarted(true);
    }

    /**
     * Creates and places players and figurines
     */
    public void createMultiplayerPlayers() {
        for(int i = 0; i < this.gameInfo.getNumberOfPlayers(); i++) {
            if(this.gameInfo.getYourPosition() == i) {
                this.gameInfo.getPlayers()[i] = new Player(this.gameInfo.getGraphicMode(), this.gameInfo.getChosenFigurine(), i, this.gameInfo.getPlayerNickname(i));
                this.gameInfo.getPlayers()[i].addMouseListener(this.gameInfo.getPlayers()[i]);
                this.gameInfo.getPlayers()[i].setUserControled(true);
            }
            else {
                if(i == this.gameInfo.getChosenFigurine()) {
                    this.gameInfo.getPlayers()[i] = new Player(this.gameInfo.getGraphicMode(), 0, i, this.gameInfo.getPlayerNickname(i));
                }
                else {
                    this.gameInfo.getPlayers()[i] = new Player(this.gameInfo.getGraphicMode(), i, i, this.gameInfo.getPlayerNickname(i));
                }
            }
        }
    }

    /**
     * Creates and places players and figurines
     */
    public void createSingleplayerPlayers() {
        if(this.gameInfo.getPlayers() != null) {
            this.gameInfo.setPlayers(null);
        }
        Player[] players = new Player[this.gameInfo.getNumberOfPlayers()];
        for(int i = 0; i < this.gameInfo.getNumberOfPlayers(); i++) {
            if(i == 0) {
                players[i] = new Player(this.gameInfo.getGraphicMode(), this.gameInfo.getChosenFigurine(), i, this.gameInfo.getPlayerNickname(0));
                players[i].addMouseListener(players[i]);
                players[i].setUserControled(true);
            }
            else {
                if(i == this.gameInfo.getChosenFigurine()) {
                    players[i] = new AiPlayer(this.gameInfo.getGraphicMode(), 0, i);
                }
                else {
                    players[i] = new AiPlayer(this.gameInfo.getGraphicMode(), i, i);
                }
                players[i].addMouseListener(players[i]);
            }
        }
        this.gameInfo.setPlayers(players);
    }

    public void loadPlayers() {
        Player[] players = new Player[this.gameInfo.getNumberOfPlayers()];
        AiPlayer cpu1 = null, cpu2 = null;

        for(int i = 0; i < this.gameInfo.getNumberOfPlayers(); i++) {
            if(i == 0) {
                players[i] = this.load.getPlayers()[i];
                players[i].addMouseListener(players[i]);
                players[i].setUserControled(true);
            }
            else {
                if(i == this.gameInfo.getChosenFigurine()) {
                    players[i] = this.load.getPlayers()[i];
                }
                else {
                    players[i] = this.load.getPlayers()[i];
                }
                players[i].addMouseListener(players[i]);
                cpu2 = (AiPlayer) this.load.getPlayers()[i];
                cpu1 = (AiPlayer) players[i];
                cpu1.setRandomMove(cpu2.getRandomMove());
                cpu1.setPreferHome(cpu2.getPreferHome());
                cpu1.setPreferNew(cpu2.getPreferNew());
            }
        }
        System.out.println("NUMBER OF PLAYERS: " + this.gameInfo.getNumberOfPlayers());
        for(int i = 0; i < this.gameInfo.getNumberOfPlayers(); i++) {
            for(int j = 0; j < 4; j++) {
                players[i].getFigurines()[j].setActualPosition(this.load.getPlayers()[i].getFigurines()[j].getActualPosition());
                players[i].getFigurines()[j].setStartingPosition(this.load.getPlayers()[i].getFigurines()[j].getStartingPosition());
                players[i].getFigurines()[j].setCounter(this.load.getPlayers()[i].getFigurines()[j].getCounter());
                if(players[i].getFigurines()[j].getActualPosition() != -1) {
                    players[i].getFigurines()[j].setBounds(this.gameInfo.getFields()[players[i].getFigurines()[j].getActualPosition()].getX(), this.gameInfo.getFields()[players[i].getFigurines()[j].getActualPosition()].getY(), 40, 40);
                    this.gameInfo.getFields()[players[i].getFigurines()[j].getActualPosition()].setOccupied(true);
                }
            }
        }
        this.gameInfo.setPlayers(players);
    }

    /*
     * Creates and places game fields accordingly to players choice
     */
    public void createGameFields(int[] rV) {
        /*
         * Already created game board is freed
         */
        if(this.gameInfo.getFields() != null) {
            this.gameInfo.setFields(null);
        }
        
        int[] randomValues = new int[6];
        if(rV == null) {
            /*
             * Generating sequence of random integers
             */
            Random generator = new Random();
            int randomValue;
            for(int i = 0; i < 6; i++) {
                randomValues[i] = -1;
            }
            for(int i = 0; i < 6; i++) {
                randomValue = generator.nextInt(6);
                for(int j = 0; j <= i; j++) {
                    if(randomValue == randomValues[j]) {
                        randomValue = generator.nextInt(6);
                        j = -1;
                    }
                    if(j == i) {
                        randomValues[j] = randomValue;
                    }
                }
            }
        }
        else {
            randomValues = rV;
        }
        this.gameInfo.setGeneratedValues(randomValues);

        /*
         * Creating game fields
         */
        int gameBoardSize = this.gameInfo.getGameBoardSize();
        GameField[] fields = new GameField[gameBoardSize+4*this.gameInfo.getNumberOfPlayers()];
        for(int i = 0; i < gameBoardSize+4*this.gameInfo.getNumberOfPlayers(); i++) {
            fields[i] = new GameField(this.gameInfo.getGraphicMode(),randomValues[i%6],i);
            fields[i].addMouseListener(fields[i]);
        }

        /*
         * Placing game fiels to their correct positions
         */
        if(gameBoardSize == 36) {
            this.createSmallGameBoard(fields);
        }
        else if(gameBoardSize == 48) {
            this.createMediumGameBoard(fields);
        }
        else if(gameBoardSize == 60) {
            this.createLargeGameBoard(fields);
        }
        
    }

    /*
     * Variation on Midpoint algorithm for ellipse,
     *  version for small GameBoard (36 game fields)
     * Function places game fields in their correct position
     * @param fields array of game fields
     */
    private void createSmallGameBoard(GameField[] fields) {
        int x=0, y = 0, size = 40;
        int transposeX = 384, transeposeY = 174;
        /*
         * setting game fields to their correct positions
         */
        for(int i = 0; i < 9; i++) {
            fields[i].setBounds(x+transposeX, y+transeposeY, size, size);
            fields[27+i].setBounds(y-200+transposeX, -x+160+transeposeY, size, size);
            fields[18+i].setBounds(-x-40+transposeX, -y+360+transeposeY, size, size);
            fields[9+i].setBounds(-y+160+transposeX, x+200+transeposeY, size, size);
            if(i == 0) {x += 40;}
            if(i == 1) {y += 40;}
            if(i == 2) {y += 40;}
            if(i == 3) {y += 40;}
            if(i == 4) {x += 40;}
            if(i == 5) {x += 40;}
            if(i == 6) {x += 40;}
            if(i == 7) {y += 40;}
        }
        /*
         * setting houses to their correct positions
         */
        for(int i = 0; i < this.gameInfo.getNumberOfPlayers(); i++) {
            if(i == 0) {x = fields[26].getX()-80; y = fields[26].getY();}
            //if(i == 0) {fields[26].setVisible(false);}
            if(i == 1) {x = fields[8].getX()+80; y = fields[8].getY();}
            //if(i == 1) {fields[8].setVisible(false);}
            if(i == 2) {x = fields[35].getX(); y = fields[35].getY()-80;}
            //if(i == 2) {fields[35].setVisible(false);}
            if(i == 3) {x = fields[17].getX(); y = fields[17].getY()+80;}
            //if(i == 3) {fields[17].setVisible(false);}
            for(int j = 0; j < 4; j++) {
                fields[this.gameInfo.getGameBoardSize()+i*4+j].setBounds(x, y, size, size);
                fields[this.gameInfo.getGameBoardSize()+i*4+j].setSaveHouse(true);
                fields[this.gameInfo.getGameBoardSize()+i*4+j].setText("" + i);
                if(i == 0) {
                    if(j == 0) x-=40;
                    else if(j == 1) y+=40;
                    else if(j == 2) x+=40;
                }
                if(i == 1) {
                    if(j == 0) x+=40;
                    else if(j == 1) y-=40;
                    else if(j == 2) x-=40;
                }
                if(i == 3) {
                    if(j == 0) y+=40;
                    else if(j == 1) x+=40;
                    else if(j == 2) y-=40;
                }
                if(i == 2) {
                    if(j == 0) y-=40;
                    else if(j == 1) x-=40;
                    else if(j == 2) y+=40;
                }
            }
        }
        this.gameInfo.setFields(fields);
    }

    /*
     * Variation on Midpoint algorithm for ellipse,
     *  version for medium GameBoard (48 game fields)
     * Function places game fields in their correct position
     * @param fields array of game fields
     */
    private void createMediumGameBoard(GameField[] fields) {
        int x=0,y=0,size=40;
        int transposeX = 384, transeposeY = 114;
        /*
         * setting game fields to their correct positions
         */
        for(int i = 0; i < 12; i++) {
            fields[i].setBounds(x+transposeX, y+transeposeY, size, size);
            fields[36+i].setBounds(y-240+transposeX, -x+240+transeposeY, size, size);
            fields[24+i].setBounds(-x+transposeX, -y+480+transeposeY, size, size);
            fields[12+i].setBounds(-y+240+transposeX, x+240+transeposeY, size, size);
            if(i == 0) {x += 40;}
            if(i == 1) {x += 40;}
            if(i == 2) {y += 40;}
            if(i == 3) {y += 40;}
            if(i == 4) {y += 40;}
            if(i == 5) {y += 40;}
            if(i == 6) {x += 40;}
            if(i == 7) {x += 40;}
            if(i == 8) {x += 40;}
            if(i == 9) {x += 40;}
            if(i == 10) {y += 40;}
        }
        /*
         * setting houses to their correct positions
         */
        for(int i = 0; i < this.gameInfo.getNumberOfPlayers(); i++) {
            if(i == 0) {x = fields[36].getX()+40; y = fields[36].getY();}
            //if(i == 0) {fields[17].setVisible(false);}
            if(i == 1) {x = fields[12].getX()-40; y = fields[12].getY();}
            //if(i == 1) {fields[12].setVisible(false);}
            if(i == 2) {x = fields[0].getX(); y = fields[0].getY()+40;}
            //if(i == 2) {fields[17].setVisible(false);}
            if(i == 3) {x = fields[24].getX(); y = fields[24].getY()-40;}
            //if(i == 2) {fields[17].setVisible(false);}
            for(int j = 0; j < 4; j++) {
                fields[this.gameInfo.getGameBoardSize()+i*4+j].setBounds(x, y, size, size);
                fields[this.gameInfo.getGameBoardSize()+i*4+j].setSaveHouse(true);
                if(i == 0) {x+=40;}
                if(i == 1) {x-=40;}
                if(i == 2) {y+=40;}
                if(i == 3) {y-=40;}
            }
        }
        this.gameInfo.setFields(fields);
    }

    /*
     * Variation on Midpoint algorithm for ellipse,
     *  version for large GameBoard (48 game fields)
     * Function places game fields in their correct position
     * @param fields array of game fields
     */
    private void createLargeGameBoard(GameField[] fields) {
        int x=0,y=0,size=40;
        int transposeX = 384, transeposeY = 40;
        /*
         * setting game fields to their correct positions
         */
        for(int i = 0; i < 15; i++) {
            fields[i].setBounds(x+transposeX, y+transeposeY, size, size);
            fields[45+i].setBounds(y-320+transposeX, -x+280+transeposeY, size, size);
            fields[30+i].setBounds(-x-40+transposeX, -y+600+transeposeY, size, size);
            fields[15+i].setBounds(-y+280+transposeX, x+320+transeposeY, size, size);
            if(i == 0) {x += 40;}
            if(i == 1) {x += 40;}
            if(i == 2) {y += 40;}
            if(i == 3) {y += 40;}
            if(i == 4) {y += 40;}
            if(i == 5) {y += 40;}
            if(i == 6) {y += 40;}
            if(i == 7) {x += 40;}
            if(i == 8) {x += 40;}
            if(i == 9) {x += 40;}
            if(i == 10) {x += 40;}
            if(i == 11) {x += 40;}
            if(i == 12) {y += 40;}
            if(i == 13) {y += 40;}
        }
        /*
         * setting houses to their correct positions
         */
        for(int i = 0; i < this.gameInfo.getNumberOfPlayers(); i++) {
            if(i == 0) {x = fields[45].getX()+40; y = fields[45].getY();}
            if(i == 1) {x = fields[15].getX()-40; y = fields[15].getY();}
            if(i == 2) {x = fields[0].getX(); y = fields[0].getY()+40;}
            if(i == 3) {x = fields[30].getX(); y = fields[30].getY()-40;}
            for(int j = 0; j < 4; j++) {
                fields[this.gameInfo.getGameBoardSize()+i*4+j].setBounds(x, y, size, size);
                fields[this.gameInfo.getGameBoardSize()+i*4+j].setSaveHouse(true);
                if(i == 0) {x+=40;}
                if(i == 1) {x-=40;}
                if(i == 2) {y+=40;}
                if(i == 3) {y-=40;}
            }
        }
        this.gameInfo.setFields(fields);
    }

    public void setInfoPanel(GameInfoPanel panel) {
        this.infoPanel = panel;
    }

    public GameInfoPanel getInfoPanel() {
        return this.infoPanel;
    }

    public void setGameFrame(GameFrame frame) {
        this.gameFrame = frame;
    }

    public GameFrame getGameFrame() {
        return this.gameFrame;
    }
}
